package com.inspection.service.impl;

import com.google.common.collect.Lists;
import com.inspection.constant.EventApproveStatusEnum;
import com.inspection.constant.YesNoEnum;
import com.inspection.dao.InspectionBranchDao;
import com.inspection.dao.InspectionEventDao;
import com.inspection.entity.InspectionBranchDO;
import com.inspection.entity.InspectionEventDO;
import com.inspection.model.dto.InspectionChartDTO;
import com.inspection.model.dto.InspectionRegulationQueryDTO;
import com.inspection.model.vo.chart.*;
import com.inspection.service.InspectionRegulationService;
import com.inspection.service.InspectionChartService;
import com.inspection.support.model.BusinessBaseException;
import com.inspection.support.model.DataTree;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Example;
import org.springframework.data.jpa.domain.Specification;
import org.springframework.stereotype.Service;
import org.springframework.util.CollectionUtils;

import javax.persistence.criteria.Predicate;
import java.util.*;
import java.util.stream.Collectors;

/**
 * @author zhaoqi
 * @since 2020-12-03
 */
@Service
public class InspectionChartServiceImpl implements InspectionChartService {
    @Autowired
    private InspectionRegulationService inspectionRegulationService;

    @Autowired
    private InspectionEventDao inspectionEventDao;

    @Autowired
    private InspectionBranchDao inspectionBranchDao;
    /**
     * 考核生态
     *
     * @param query
     * @return
     */
    @Override
    public InspectionEcologyCycleVO ecology(InspectionChartDTO query) {

        query.validate();
        Date startDate = getDate(query,false);
        Date endDate = getDate(query,true);

        //查询考核的条例下最顶级的考核条例
        //直接拿到考核条例树   也可以指定的拿单独某个类型的树 fixme
        DataTree regulationTree = inspectionRegulationService.getRegulationTree(new InspectionRegulationQueryDTO());


        DataTree.TreeNode inspectTopNode=null;
        List<DataTree.TreeNode> topRegu = regulationTree.getRootNode().getChildren();
        for (DataTree.TreeNode treeNode : topRegu) {
            if (treeNode.getInspectionType().equals(query.getInspectionType())) {
                inspectTopNode= treeNode;
                break;
            }
        }
        if (inspectTopNode == null) {
            throw new BusinessBaseException("考核类型不存在！");
        }
        List<DataTree.TreeNode> secTopNodeList = inspectTopNode.getChildren();    //次顶级的考核条例

        //每个次顶级条例 下面可执行的考核条例的idList      条例ID -孩子节点下所有的可执行条例id
        Map<Long,List<Long>>  reguChildrenMap  =new HashMap<>();
        Map<Long,DataTree.TreeNode>  regulationMap  =new HashMap<>();

        for (DataTree.TreeNode node : secTopNodeList) {
            List<Long> regulationIdList = new ArrayList<>();
            findCanExecute(node, regulationIdList);
            reguChildrenMap.put(node.getId(), regulationIdList);
            regulationMap.put(node.getId(), node);
        }


        //拿到这个范围内 所有的这个考核类型下的考核事件
        Specification<InspectionEventDO> specification = (Specification<InspectionEventDO>) (root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> predicates = Lists.newArrayList();
            predicates.add(criteriaBuilder.equal(root.get("inspectionType"), query.getInspectionType()));
            predicates.add(criteriaBuilder.equal(root.get("approveStatus"), EventApproveStatusEnum.APPROVE_STATUS.getStatus()));

            predicates.add(criteriaBuilder.greaterThanOrEqualTo(root.get("eventInspectDate"),startDate));
            predicates.add(criteriaBuilder.lessThan(root.get("eventInspectDate"),endDate));

            return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
        };

        List<InspectionEventDO> events = inspectionEventDao.findAll(specification);
        if(CollectionUtils.isEmpty(events)){
            return InspectionEcologyCycleVO
                    .builder()
                    .year(query.getYear())
                    .inspectionCycle(query.getInspectionCycle())
                    .InspectionType(query.getInspectionType())
                    .inspectionCycleNumber(query.getInspectionCycleNumber())
                    .regulationDimension(new ArrayList<>()).build();
        }

        //把这些事件用执行的考核条例进行group by    条例ID-  事件集合
        Map<Long, List<InspectionEventDO>> eventMap = events.stream().collect(Collectors.groupingBy(InspectionEventDO::getRegulationId));

        Set<Map.Entry<Long, List<Long>>> secTopReguSet = reguChildrenMap.entrySet();
        List<InspectionEcologyRegulationVO> regulationDimension = new ArrayList<>();
        for (Map.Entry<Long, List<Long>> entrySet : secTopReguSet) {
            List<InspectionEventDO> reguEventList = new ArrayList<>();

            DataTree.TreeNode node = regulationMap.get(entrySet.getKey());

            List<Long> exeRegulationIds = entrySet.getValue();
            for (Long exeRegulationId : exeRegulationIds) {
                List<InspectionEventDO> exeEvents = eventMap.get(exeRegulationId);
                if (!CollectionUtils.isEmpty(exeEvents)) {
                    reguEventList.addAll(exeEvents);
                }
            }

            Integer totalScore= 0;
            for (InspectionEventDO eventDO : reguEventList) {
               if(Objects.nonNull(eventDO.getInspectScore())){
                   totalScore+=eventDO.getInspectScore();
               }
            }
            regulationDimension.add(InspectionEcologyRegulationVO
                    .builder()
                    .regulationId(node.getId())
                    .regulationNo(node.getRegulationNo())
                    .regulationName(node.getRegulationName())
                    .regulationContent(node.getRegulationContent())
                    .events(reguEventList).
                    totalScore(totalScore)
                    .build());


        }
        return InspectionEcologyCycleVO
                .builder()
                .year(query.getYear())
                .inspectionCycle(query.getInspectionCycle())
                .InspectionType(query.getInspectionType())
                .inspectionCycleNumber(query.getInspectionCycleNumber())
                .regulationDimension(regulationDimension).build();
    }

    @Override
    public InspectionExecuteDeptAnalyzeVO executeDeptAnalyze(InspectionChartDTO query) {
        query.validate();
        Date startDate = getDate(query,false);
        Date endDate = getDate(query,true);

        //拿到这个范围内 所有的这个考核类型下的考核事件
        Specification<InspectionEventDO> specification = (Specification<InspectionEventDO>) (root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> predicates = Lists.newArrayList();
            predicates.add(criteriaBuilder.equal(root.get("inspectionType"), query.getInspectionType()));
            predicates.add(criteriaBuilder.equal(root.get("approveStatus"), EventApproveStatusEnum.APPROVE_STATUS.getStatus()));

            predicates.add(criteriaBuilder.greaterThanOrEqualTo(root.get("eventInspectDate"),startDate));
            predicates.add(criteriaBuilder.lessThan(root.get("eventInspectDate"),endDate));

            return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
        };

        List<InspectionEventDO> events = inspectionEventDao.findAll(specification);

        //根据考核的部门id进行groupBy

        Map<Long, List<InspectionEventDO>> eventMap = events.stream().collect(Collectors.groupingBy(InspectionEventDO::getExecuteDept));


          List<InspectionExecuteDeptVO> deptVOList = new ArrayList<>();

        Set<Map.Entry<Long, List<InspectionEventDO>>> entries = eventMap.entrySet();
        for (Map.Entry<Long, List<InspectionEventDO>> entry : entries) {
            List<InspectionEventDO> tEvents = entry.getValue();

            deptVOList.add(InspectionExecuteDeptVO
                    .builder()
                    .deptId(entry.getKey())
                    .deptName(tEvents.get(0).getExecuteDeptName()).events(tEvents)
                    .eventCount(tEvents.size())
                    .build());
        }

        return InspectionExecuteDeptAnalyzeVO.builder().deptList(deptVOList).build();
    }

    @Override
    public InspectionEventCorrectInfoVO eventCorrectAnalyze(InspectionChartDTO query) {

        query.validate();
        Date startDate = getDate(query,false);
        Date endDate = getDate(query,true);

        //拿到这个范围内 所有的这个考核类型下的考核事件
        Specification<InspectionEventDO> specification = (Specification<InspectionEventDO>) (root, criteriaQuery, criteriaBuilder) -> {
            List<Predicate> predicates = Lists.newArrayList();
            predicates.add(criteriaBuilder.equal(root.get("inspectionType"), query.getInspectionType()));
            predicates.add(criteriaBuilder.equal(root.get("approveStatus"), EventApproveStatusEnum.APPROVE_STATUS.getStatus()));

            predicates.add(criteriaBuilder.greaterThanOrEqualTo(root.get("eventInspectDate"),startDate));
            predicates.add(criteriaBuilder.lessThan(root.get("eventInspectDate"),endDate));

            return criteriaBuilder.and(predicates.toArray(new Predicate[predicates.size()]));
        };

        List<InspectionEventDO> events = inspectionEventDao.findAll(specification);
        
        Map<Long, List<InspectionEventDO>> eventMap = events.stream().collect(Collectors.groupingBy(InspectionEventDO::getInspectBranch));

        InspectionBranchDO branchQuery = new InspectionBranchDO();
        branchQuery.setIsDel(0);
        List<InspectionBranchDO> branchList = inspectionBranchDao.findAll(Example.of(branchQuery));

        List<InspectionBranchEventCorrectVO> branchResList=new ArrayList<>();
        for (InspectionBranchDO branch : branchList) {
            InspectionBranchEventCorrectVO branchEventCorrect = InspectionBranchEventCorrectVO.builder().branchId(branch.getId()).branchName(branch.getBranchName()).build();
            List<InspectionEventDO> bEvents = eventMap.get(branch.getId());

            if(CollectionUtils.isEmpty(bEvents)){
                bEvents=new ArrayList<>();
            }

            branchEventCorrect.setEvents(bEvents);
            branchEventCorrect.setEventCount(bEvents.size());
            Integer correctCount=0;
            for (InspectionEventDO eventDO : bEvents) {
                if (YesNoEnum.YES.getVal() == eventDO.getIsCorrect()) {
                    correctCount++;
                }
            }
            branchEventCorrect.setEventCorrectedCount(correctCount);
            branchEventCorrect.setEventUnCorrectCount(bEvents.size()-correctCount);

            branchResList.add(branchEventCorrect);
        }


        return InspectionEventCorrectInfoVO.builder().branchInfos(branchResList).build();
    }

    private void findCanExecute(DataTree.TreeNode node, List<Long> regulationIdList) {
        if (Objects.isNull(node)) {
            return;
        }
        if (node.getIsLeafNode() == 1) {
            regulationIdList.add(node.getId());
            return;
        }
        List<DataTree.TreeNode> children = node.getChildren();
        if (CollectionUtils.isEmpty(children)) {
            return;
        }
        for (DataTree.TreeNode child : children) {
            findCanExecute(child, regulationIdList);
        }

    }


    private Date getDate(InspectionChartDTO query, boolean end){
        Calendar calendar = Calendar.getInstance();
        calendar.set(Calendar.YEAR,query.getYear());
        calendar.set(Calendar.DAY_OF_MONTH,1);
        calendar.set(Calendar.HOUR_OF_DAY,0);
        calendar.set(Calendar.MINUTE,0);
        calendar.set(Calendar.SECOND,0);
        calendar.set(Calendar.MILLISECOND,0);

        switch (query.getInspectionCycle()) {
            case "月" :
                if(query.getInspectionCycleNumber()>12 || query.getInspectionCycleNumber() <1){
                    throw new RuntimeException("传入考核周期非法！");
                }
                calendar.set(Calendar.MONTH,query.getInspectionCycleNumber()-1);
                if(end){
                    calendar.add(Calendar.MONTH,1);
                }
                break;
            case "季" :
                if(query.getInspectionCycleNumber()>4 || query.getInspectionCycleNumber() <1){
                    throw new RuntimeException("传入考核周期非法！");
                }
                calendar.set(Calendar.MONTH,(query.getInspectionCycleNumber()-1)*3);
                if(end){
                    calendar.add(Calendar.MONTH,3);
                }
                break;
            case "半年" :
                if(query.getInspectionCycleNumber()>2 || query.getInspectionCycleNumber() <1){
                    throw new RuntimeException("传入考核周期非法！");
                }
                calendar.set(Calendar.MONTH,(query.getInspectionCycleNumber()-1)*6);
                if(end){
                    calendar.add(Calendar.MONTH,6);
                }
                break;
            case "年" :
                calendar.set(Calendar.MONTH,0);
                if(end){
                    calendar.add(Calendar.MONTH,12);
                }
                break;
            default:
                throw new RuntimeException("传入考核周期非法！");
        }
        return calendar.getTime();
    }
}
